package com.fingard.dsp.bank.directbank.epay02;

import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.DirectBase;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class EPAY02Base extends DirectBase {
    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }

    /**
     * 将MAP转换为post请求串
     * @return
     */
    public String convertMapToStr(Map<String,Object> params) {
        String reqStr = "";
        for (String key : params.keySet()) {
            if (!key.equals("")) {
                if (reqStr.length() > 0) {
                    reqStr += "&";
                }
                reqStr += key + "=" + params.get(key);
            }
        }
        return reqStr;
    }

    public Map<String,Object> convertMapToMap(Map<String,Object> maps) {
        if (maps != null) {
            Map<String,Object> params = new HashMap<String,Object>();
            for (String key : maps.keySet()) {
                Object value = maps.get(key);
                key = key.trim();
                params.put(key, value);
            }
            return params;
        }
        return null;
    }

    /**
     * 函数功能：敏感信息加密,AES算法为AES/CBC/PKCS5Padding
     * 参数：key，16位随机字符串
     * 参数：tobeEncoded，待加密的字符串，如银行卡号，V5版中的数字信封明文
     * 参数：iv,AES加密用到的IV值，V3，V4版本接口为固定值1234567892546398，V5版本接口随商户证书一起提供
     * * */
    public  String encode(String key,String tobeEncoded,String iv)throws Exception{
        //1.AES加密
        Key k =  new SecretKeySpec(key.getBytes(getCharset()), "AES");
        IvParameterSpec ivs = new IvParameterSpec(iv.getBytes());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, k, ivs);
        byte[] bytes=cipher.doFinal(tobeEncoded.getBytes(getCharset()));
        //2.BASE64编码
        return new String(Base64.encode(bytes));
    }

    /**
     * 函数功能 :RSA非对称加密，用于对16位的AES秘钥进行加密,算法为RSA/ECB/PKCS1Padding
     * 参数：TobeEncryptMsg待加密的字符串，如16位AES秘钥
     * */
    public String rsaEncode(String TobeEncryptMsg, ActSetItem actItem){
        //获取公钥
        Cipher instance;
        try {
            instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            instance.init(Cipher.ENCRYPT_MODE, base64StrToCert(actItem.oppCertFilePath));
            byte[] bytes=instance.doFinal(TobeEncryptMsg.getBytes());
            return new String(Base64.encode(bytes));
        } catch (Exception e) {
            throw new RuntimeException("RSA加密失败", e);
        }

    }

    public PublicKey base64StrToCert(String base64Cert) {
        try {
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            FileInputStream streamCert = new FileInputStream(base64Cert);

            X509Certificate cert = (X509Certificate) factory.generateCertificate(streamCert);
            if (cert == null) {
                throw new GeneralSecurityException("将cer从base64转换为对象失败");
            }
            return cert.getPublicKey();
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    private PrivateKey getPrivateKey(String key) {
        try {
            byte[] keyBytes = Base64.decode(key.getBytes(getCharset()));
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return privateKey;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 函数功能：使用商户私钥加签
     * 参数：tobeSigned，待加签的字符串，V3，版为json字符串，V4，V5版为用&连接起来的key=value键值对
     * 参数：algorithm,加签算法，V3，V4版本为SHA1withRSA，V5版本为SHA256withRSA
     * */
    public String sign(String tobeSigned,String algorithm, ActSetItem actItem) throws Exception {
        PrivateKey privateKey = getPrivateKey(actItem.ownKeyStorePath);
        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(privateKey);
        signature.update(tobeSigned.getBytes(getCharset()));
        byte[] signBytes=signature.sign();
        return new String(Base64.encode(signBytes));
    }

    /**
     * 发送并获取返回
     *
     * @param actItem
     *            商户配置信息
     * @param bizContent
     *            业务JSON
     * @param serviceCode
     *            当前服务
     * @return 响应JOSN
     * @throws Exception
     *             服务器请求异常
     */
    public String[] sendToBank(String tmpReqMsg, String url) throws Exception {
        String[] retStr = new String[]{"",""};
        CloseableHttpClient httpClient = HttpClients.createDefault();
        WriteBankLogLn2("服务地址:" + url);
        HttpPost httpPost = new HttpPost(url);
        StringEntity se = new StringEntity(tmpReqMsg,"UTF-8");
        se.setContentType("application/json");
        httpPost.setEntity(se);
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity1 = response.getEntity();
        if(entity1 != null){
            retStr[1] = EntityUtils.toString(entity1, "UTF-8");
        }
        WriteBankLogStep3(retStr[1]);
        httpClient.close();
        response.close();
        return retStr;
    }

    public String convertMapToSortStr(Map data) {
        StringBuilder sb = new StringBuilder();
        TreeMap<String, Object> treeMap = new TreeMap(data);
        for (Map.Entry<String, Object> ent : treeMap.entrySet()) {
            String name = ent.getKey();
            if (/* !"signType".equals(name) &&*/ !"sign".equals(name)) {
                sb.append(name).append('=').append(ent.getValue()).append('&');
            }
        }
        if (sb.length() > 0) {
            sb.setLength(sb.length() - 1);
        }
        return sb.toString();
    }


    public String getSFTPDir(String p_reqPath) {
        if (p_reqPath.endsWith("/")) {
            return p_reqPath;
        } else {
            return p_reqPath + "/";
        }
    }
}
